test(security): pin server-managed field set + tenant-wall write guard; fix systemFields docs (#3058)#3168
Merged
Conversation
…d; fix systemFields docs (#3058) #3058 proposed collapsing the three server-managed-field special cases (owner_id / public-form set / organization_id) into one declarative `systemManaged` schema concept. Assessment: the field roster is a closed set of platform columns, the three enforcement semantics are genuinely heterogeneous, and the real risk the issue names (drift between the sites) is closable without a new abstraction. This is the right-sized alternative — it hardens the drift seams and fills test gaps without introducing a speculative declaration layer. - objectql: new conformance test pinning PUBLIC_FORM_SERVER_MANAGED_FIELDS to an exact partition of (fields actually injected by applySystemFields + `id` + the `__search` companion) and (documented defense-in-depth reserved names: tenant_id / is_deleted / deleted_at). A newly-injected system field that is not added to the denylist now fails loudly here instead of leaking through the anonymous public-form surface — the drift vector that first surfaced as #3022. - plugin-security: add the missing package-level write-side unit tests for the step 3.7 organization_id tenant wall (insert forge / update re-point denied, matching-org and absent-value writes pass, isSystem exempt). Previously only the read-side Layer 0 and the multitenant dogfood covered this. - spec: correct the stale systemFields JSDoc/describe on ObjectSchema to match the registry — the organization_id column is provisioned unconditionally (only its index is multi-tenant-gated), `audit` is a wired opt-out, and owner_id provisioning is governed by the `ownership` property, not the `owner` key. No runtime behavior changes: the existing owner/tenant/public-form guards and all 209 security-plugin tests are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014343Qv6DFAykuAJc9yjANb
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 110 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 18, 2026 06:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Closes the actionable part of #3058. That issue proposed hoisting the three "server-managed field" special cases —
owner_id(step 3.5), the public-form set (PUBLIC_FORM_SERVER_MANAGED_FIELDS), andorganization_id(step 3.7) — into one declarativesystemManagedschema concept with a unified enforcement point and an ADR.After exploring the current code, the assessment is that the full declarative abstraction is not yet warranted, and the debt the issue actually names is closable without it:
This PR is the right-sized alternative: harden the drift seam, fill test gaps, and correct stale contract docs. No runtime behavior changes.
Changes
objectql — new conformance test (
system-managed-fields-conformance.test.ts) pinningPUBLIC_FORM_SERVER_MANAGED_FIELDSto an exact partition of:applySystemFields→organization_id+ audit columns +owner_id) plus the__searchcompanion and theidprimary key, andtenant_id/is_deleted/deleted_at.A newly-injected system field that isn't added to the denylist now fails here with an actionable message, instead of silently leaking through the anonymous public-form surface.
plugin-security — add the missing package-level write-side unit tests for the step 3.7
organization_idtenant wall (insert-forge and update-repoint denied; matching-org and absent-value writes pass;isSystemexempt). Previously only the read-side Layer 0 and the multitenant dogfood covered this.spec — correct the stale
systemFieldsJSDoc/describe onObjectSchemato match the registry: theorganization_idcolumn is provisioned unconditionally (only its index is multi-tenant-gated),auditis a wired opt-out, andowner_idprovisioning is governed by the object-levelownershipproperty — not theownerkey.Findings surfaced (not changed here)
#3043already closed the authenticated audit-column INSERT gap. The originally-planned follow-up (audit columns seedable on authenticated insert) is moot onmain:readonlyis now stripped on INSERT at the data-write ingress.schema.ownershipname collision. The property is read as'own' | 'extend'(metadata authorship) bypackages/cli/src/commands/info.tsand as'user' | 'org' | 'none'(record-ownership model) byregistry.tsapplySystemFields. This is why this PR does not add a typedownershipfield toObjectSchema— that would force a premature resolution of a genuine two-meanings collision. Worth its own focused issue.Verification
@objectstack/spectest — 6911 pass (describe-string change;check:livenessgreen).@objectstack/objectqlconformance + registry — pass; conformance test confirmed to bite (removingowner_idfrom the denylist fails with the intended message).@objectstack/plugin-security— fullsecurity-plugin.test.ts209 pass (6 new + all existing unchanged).🤖 Generated with Claude Code
https://claude.ai/code/session_014343Qv6DFAykuAJc9yjANb
Generated by Claude Code